﻿
using Fast.DynamicApiController.Dependencies;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ActionConstraints;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.AspNetCore.Mvc.Routing;


namespace Fast.DynamicApiController.Conventions
{
    /// <summary>
    /// 动态接口控制器应用模型转换器
    /// </summary>
    public class DynamicApiControllerApplicationModelConvention : IApplicationModelConvention
    {
        /// <summary>
        /// 配置应用模型信息
        /// </summary>
        /// <param name="application">引用模型</param>
        public void Apply(ApplicationModel application)
        {
            if (application == null)
            {
                throw new ArgumentNullException(nameof(application));
            }

            // 遍历所有控制器
            foreach (var controller in application.Controllers)
            {
                if (controller.ControllerType.IsAssignableTo(typeof(DynamicApiControllerBase)) || controller.ControllerType.IsAssignableTo(typeof(ControllerBase)))
                {
                    AddApiController(controller);
                    ConfigureControllerRouteAttribute(controller);
                    ConfigureController(controller);
                }
            }
        }

        /// <summary>
        /// 添加 [ApiController] 特性
        /// </summary>
        /// <param name="controller">控制器模型</param>
        public void AddApiController(ControllerModel controller)
        {
            // 如果控制器没有 [ApiController] 特性，则动态添加
            var apiControllerAttribute = controller.Attributes.OfType<ApiControllerAttribute>().FirstOrDefault();
            if (apiControllerAttribute == null)
            {
                // 添加ApiController特性
                controller.Filters.Add(new ApiControllerAttribute());
            }
        }

        /// <summary>
        /// 配置 Controller 路由特性
        /// </summary>
        /// <param name="controller">控制器模型</param>
        public void ConfigureControllerRouteAttribute(ControllerModel controller)
        {
            // 如果控制器没有自定义 [Route] 特性，则为其动态添加默认的 API 路由
            var routeControllerAttribute = controller.Attributes.OfType<RouteAttribute>().FirstOrDefault();
            if (routeControllerAttribute == null)
            {
                // 如果没有自定义路由，添加默认路由（api/[controller]/[action]/）
                string routeTemplate = GetRouteTemplate(controller);
                //方式一：添加特性
                //controller.Selectors.Insert(0, new SelectorModel
                //{
                //    AttributeRouteModel = new AttributeRouteModel(new RouteAttribute(routeTemplate))
                //});
                //方式二：修改路由模板
                controller.Selectors[0].AttributeRouteModel = new AttributeRouteModel
                {
                    Template = routeTemplate
                };

                // 确保路由只添加一次
                //if (controller.Selectors.Count == 0 || controller.Selectors[0].AttributeRouteModel == null)
                //{
                //    controller.Selectors.Add(new SelectorModel
                //    {
                //        AttributeRouteModel = new AttributeRouteModel(new RouteAttribute(routeTemplate))
                //    });
                //}
            }
        }

        /// <summary>
        /// 配置控制器
        /// </summary>
        /// <param name="controller">控制器模型</param>
        public void ConfigureController(ControllerModel controller)
        {
            var actions = controller.Actions;

            foreach (var action in actions)
            {
                var actionMethod = action.ActionMethod;

                // 检查当前方法是否是继承而来
                if (controller.ControllerType.IsSubclassOf(actionMethod?.DeclaringType ?? typeof(object)))
                {
                    action.ApiExplorer.IsVisible = false;
                    continue;
                }

                ConfigureHttpMethodAttribute(controller,action);
            }

        }

        /// <summary>
        /// 获取路由模板
        /// </summary>
        /// <param name="controller">控制器模型</param>
        /// <returns></returns>
        private string GetRouteTemplate(ControllerModel controller)
        {
            return $"api/{controller.ControllerName}/[action]/";
        }

        /// <summary>
        /// 获取控制器路由模板
        /// </summary>
        /// <param name="controller">控制器模型</param>
        /// <returns></returns>
        private string GetControllerRouteTemplate(ControllerModel controller)
        {
            // 检查控制器是否已有路由特性
            var controllerRoute = controller.Attributes
                .OfType<RouteAttribute>()
                .FirstOrDefault();
            if (controllerRoute == null) return "";

            return controllerRoute.Template;
        }

        /// <summary>
        /// 配置Http方法特性
        /// </summary>
        /// <param name="action">动作模型</param>
        public void ConfigureHttpMethodAttribute(ControllerModel controller,ActionModel action)
        {
            // 检查是否有 [HttpGet]、[HttpPost] 等特性，优先使用这些特性
            if (action.Attributes.OfType<HttpMethodAttribute>().Any())
                return;

            string actionName = action.ActionMethod.Name;
            var httpMethod = MapHttpMethod(actionName);

            if (httpMethod != null)
            {
                switch (httpMethod)
                {
                    case "GET":
                        action.Selectors[0].ActionConstraints.Add(new HttpMethodActionConstraint(new[] { "GET" }));
                        break;
                    case "POST":
                        action.Selectors[0].ActionConstraints.Add(new HttpMethodActionConstraint(new[] { "POST" }));
                        break;
                    case "PUT":
                        action.Selectors[0].ActionConstraints.Add(new HttpMethodActionConstraint(new[] { "PUT" }));
                        break;
                    case "DELETE":
                        action.Selectors[0].ActionConstraints.Add(new HttpMethodActionConstraint(new[] { "DELETE" }));
                        break;
                    case "PATCH":
                        action.Selectors[0].ActionConstraints.Add(new HttpMethodActionConstraint(new[] { "PATCH" }));
                        break;
                }
            }
        }

        /// <summary>
        /// 按 Action 名称获取Http方法
        /// </summary>
        /// <param name="actionName">Action 名称</param>
        /// <returns></returns>
        private string? MapHttpMethod(string actionName)
        {
            actionName = actionName.ToLowerInvariant();

            if (actionName.StartsWith("get")) return "GET";
            if (actionName.StartsWith("post")) return "POST";
            if (actionName.StartsWith("put") || actionName.StartsWith("upd")) return "PUT";
            if (actionName.StartsWith("delete")) return "DELETE";
            if (actionName.StartsWith("patch")) return "PATCH";

            // 默认使用 POST
            return "POST";
        }

    }
}
